﻿using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Windows.Media;
using ff14bot;
using ff14bot.Behavior;
using ff14bot.Helpers;
using ff14bot.Interfaces;
using ff14bot.Managers;
using ff14bot.Navigation;
using MultiBot.Settings;
using TreeSharp;
using System.Linq;
using Action = TreeSharp.Action;
using System.Threading;
using System.Runtime.InteropServices;

namespace MultiBot
{
    public class MultiBot : IBotPlugin
    {
        #region Necessary Stuff
        public string Author { get { return "Exmortem"; } }
        public Version Version { get { return new Version(1, 0); } }
        public string Name { get { return "MultiBot"; } }
        public string Description { get { return "Runs Fate Bot in conjunction with PvP bot."; } }
        public bool WantButton
        {
            get { return true; }
        }
        public string ButtonText
        {
            get { return "MultiBot"; }
        }
        public void OnButtonPress()
        {
            if (_form == null || _form.IsDisposed || _form.Disposing)
                _form = new MultiBotForm();

            _form.ShowDialog();  
        }
        public bool Equals(IBotPlugin other)
        {
            throw new NotImplementedException();
        }
        #endregion

        private Composite Root;
        public static MultiBotSettings settings = MultiBotSettings.instance;
        private MultiBotForm _form;

        #region Init
        public void OnInitialize()
        {

        }
        public void OnShutdown()
        {

        }
        public void OnEnabled()
        {
            Logging.Write(Colors.Gold, "[MultiBot] Enabled");

            Root = CreateBehaviorLogic();
            Root.Start(null);
        }
        public void OnDisabled()
        {
            Logging.Write(Colors.Gold, "[MultiBot] Disabled");

            Root.Stop(null);
            Root = null;

        }
        #endregion

        private static Composite CreateBehaviorLogic()
        {
            return new PrioritySelector(
                
                new Decorator(r => InPvpZone && BotManager.Current.Name == "PvP", new Action(r => new ActionAlwaysSucceed())),

                #region PvP
                new Decorator(r => BotManager.Current.Name == "PvP",
                    new PrioritySelector(
                        new Decorator(r => DutyManager.InQueue && !InPvpZone,
                            new Action(r => ChangeBot(settings.WhichBotToRun)))

                         )),
                #endregion

                new Decorator(r => BotManager.Current.Name == settings.WhichBotToRun,
                    new PrioritySelector(

                        //I wanna make sure that we always stay queued but don't wanna transition unless we're in a position where we can, ie: not in combat.
                        new Decorator(r => (!DutyManager.InQueue || DutyManager.DutyReady) && !Core.Player.InCombat && !GatheringWindow.WindowOpen,
                            new PrioritySelector(
                                //Switch Jobs before going back to PvP bot so we can accept queue.
                                new Decorator(r => IsDiscipleOfHand(), new Action(r => { ChangeJob(); ChangeBot("PvP"); })),
                                new Action(r => ChangeBot("PvP"))

                                )),

                        //Switch Jobs back to Disciple of the Hand if we're running a gathering or crafting bot.
                        new Decorator(r => (BotManager.Current.Name == "Gathering" || BotManager.Current.Name == "Fishing") && !IsDiscipleOfHand(), new Action(r => ChangeJob()))
                       
                        ))
            );
        }

        private static bool InPvpZone
        {
            get
            {
                return WorldManager.ZoneId == 337 || WorldManager.ZoneId == 336 || WorldManager.ZoneId == 175;
            }
        }

        public static void ChangeBot(string bot)
        {
                ThreadPool.QueueUserWorkItem(o =>
                {
                    try
                    {
                        Navigator.Stop();
                        TreeRoot.Stop();
                        Thread.Sleep(1500);
                        BotManager.SetCurrent(BotManager.Bots.FirstOrDefault(u => u.Name.Contains(bot)));
                        Logging.Write(Colors.Gold, "[MultiBot] Changed BotBase to " + bot);
                        Thread.Sleep(1500);
                        TreeRoot.Start();
                    }
                    catch (Exception treerootexception)
                    {
                        Logging.Write(Colors.Red, "[MultiBot] Error: {0}", treerootexception);
                    }
                });
            
        }

        #region Keyboard change class.

        [DllImport("user32.dll")]
        public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        public static void ChangeJob()
        {
            Navigator.Stop();

            const uint WM_KEYDOWN = 0x100;
            const uint WM_KEYUP = 0x0101;

            PostMessage(Core.Memory.Process.MainWindowHandle, WM_KEYDOWN, (IntPtr)(Keys.D7), IntPtr.Zero);
            PostMessage(Core.Memory.Process.MainWindowHandle, WM_KEYUP, (IntPtr)(Keys.D7), IntPtr.Zero);

            Thread.Sleep(5000);
            Logging.Write(Colors.Gold, "[MultiBot] Changing Job");
        }
        #endregion

        public static bool IsDiscipleOfHand()
        {
            if (Core.Player.CurrentJob.ToString() == "Botanist" || Core.Player.CurrentJob.ToString() == "Fisher" ||
                Core.Player.CurrentJob.ToString() == "Miner")
                return true;

            return false;
        }

        #region Pulse
        public void OnPulse()
        {
            try
            {
                Root.Tick(null);
                if (Root.LastStatus != RunStatus.Running)
                {
                    Root.Stop(null);
                    Root.Start(null);
                }
            }
            catch (Exception e)
            {
                Logging.WriteException(e);
                Root.Stop(null);
                Root.Start(null);
                throw;
            }
        }
        #endregion
    }
}